using System;
using DevExpress.Data.Filtering;
using DevExpress.Xpo;
using SmartPeople.Framework.SecuritySpace;
using SmartPeople.Framework.SecuritySpace;

namespace SmartPeople.Framework.Security.Providers.XPO
{
    //TODO: Checks for nulls!!!
    /// <remarks>
    /// The provider has more of the database interaction stuff.
    /// </remarks>
    internal class XPSecurityPermissionProvider : ISecurityPermissionsProvider
    {
        /// <summary>
        /// Gets the count.
        /// </summary>
        /// <value>The count.</value>
        public int Count
        {
            get
            {
                XPCollection<XPSecurityPermission> xpCollection = new XPCollection<XPSecurityPermission>();
                return xpCollection.Count;
            }
        }


        private static XPCollection<XPSecurityPermission> GetPermissions(Guid securityRoleID, Guid securedDocumentID,
                                                                         Guid actionID, Guid stateID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", securityRoleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", securedDocumentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            criteriaOperatorCollection.Add(new BinaryOperator("StateID", stateID));

            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            return new XPCollection<XPSecurityPermission>(criteriaOperator);
        }


        public AccessType GetAccessType(Guid roleID, Guid documentID, Guid actionID, Guid stateID)
        {
            //get the type of access for the given parameters

            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            criteriaOperatorCollection.Add(new BinaryOperator("StateID", stateID));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            //ISecurityPermission SecurityPermission =  XPCollection<XPSecurityPermission>(criteriaOperator);
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteriaOperator);

            if (xpCollection.Count == 1)
            {
                XPSecurityPermission SecurityPermission = (XPSecurityPermission) xpCollection[0];
                return SecurityPermission.AccessType;
            }
            //TODO:Test this 
            //return allow as the default access type
            return AccessType.Inherited;
            //return null;
        }

        public ISecurityPermission GetPermission(Guid roleID, Guid documentID, Guid actionID, Guid stateID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            criteriaOperatorCollection.Add(new BinaryOperator("StateID", stateID));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            //ISecurityPermission SecurityPermission =  XPCollection<XPSecurityPermission>(criteriaOperator);
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteriaOperator);

            if (xpCollection.Count == 1)
            {
                XPSecurityPermission SecurityPermission = (XPSecurityPermission) xpCollection[0];
                return SecurityPermission;
            }
            //TODO:Test this 
            //return allow as the default access type
            return null;
        }

        public ISecurityPermission CreatePermission(Guid securityRoleID, Guid securedDocumentID,
                                                    Guid actionID, Guid stateID, AccessType accessType)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", securityRoleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", securedDocumentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            criteriaOperatorCollection.Add(new BinaryOperator("StateID", stateID));
//          criteriaOperatorCollection.Add(new BinaryOperator("AccessType", accessType));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            //ISecurityPermission SecurityPermission =  XPCollection<XPSecurityPermission>(criteriaOperator);
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteriaOperator);
            if (xpCollection.Count == 1)
            {
                XPSecurityPermission SecurityPermission = (XPSecurityPermission) xpCollection[0];
                //SecurityPermission.ActionID = actionID;
                //SecurityPermission.StateID = stateID;
                SecurityPermission.AccessType = accessType;
                SecurityPermission.Save();
                return SecurityPermission;
            }
            else
            {
                XPSecurityPermission securityPermission = new XPSecurityPermission();
                securityPermission.SecurityRoleID = securityRoleID;
                securityPermission.SecuredDocumentID = securedDocumentID;
                securityPermission.ActionID = actionID;
                securityPermission.StateID = stateID;
                securityPermission.AccessType = accessType;
                securityPermission.Save();
                return securityPermission;
            }
        }


        public bool UpdatePermission(ISecurityPermission permission)
        {
            if (permission == null) throw new ArgumentNullException("permission");
            XPSecurityPermission securityPermission = (XPSecurityPermission) permission;
            if (securityPermission != null)
            {
                securityPermission.Save();
                return true;
            }
            else
            {
                return false;
            }
        }


        public bool DeletePermission(Guid permissionID)
        {
            XPSecurityPermission securityPermission = (XPSecurityPermission) GetPermissions(permissionID);
            if (securityPermission == null)
                return false;
            else
            {
                securityPermission.Delete();
                securityPermission.Session.PurgeDeletedObjects();
                return true;
            }
        }


        public bool DeletePermission(ISecurityPermission permission)
        {
            if (permission == null)
            {
                throw new ArgumentException("Permission cannot be null!");
            }
            XPSecurityPermission securityPermission = (XPSecurityPermission) permission;
            if (securityPermission == null)
                return false;
            else
            {
                securityPermission.Delete();
                securityPermission.Session.PurgeDeletedObjects();
                return true;
            }
        }

        public bool DeletePermission(Guid roleID, Guid documentID, Guid actionID, Guid stateID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            criteriaOperatorCollection.Add(new BinaryOperator("StateID", stateID));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteriaOperator);
            if (xpCollection.Count == 1)
            {
                XPSecurityPermission SecurityPermission = (XPSecurityPermission) xpCollection[0];
                SecurityPermission.Delete();
                SecurityPermission.Session.PurgeDeletedObjects();
                return true;
            }
            return false;
        }

        public bool DeletePermission(Guid roleID, Guid documentID, Guid actionID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));
            criteriaOperatorCollection.Add(new BinaryOperator("ActionID", actionID));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            XPCollection xpCollection = new XPCollection(typeof(XPSecurityPermission), criteriaOperator);
            foreach (XPSecurityPermission SecurityPermission in xpCollection)
            {
                SecurityPermission.Delete();
                SecurityPermission.Session.PurgeDeletedObjects();
                return true;
            }

            return false;
        }


        public bool DeletePermission(Guid roleID, Guid documentID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));
            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteriaOperator);
            foreach (XPSecurityPermission SecurityPermission in xpCollection)
            {
                SecurityPermission.Delete();
                SecurityPermission.Session.PurgeDeletedObjects();
                return true;
            }

            return false;
        }


        public ISecurityPermission GetPermissions(Guid permissionID)
        {
            GroupOperator criteria = new GroupOperator();
            criteria.Operands.Add(new BinaryOperator("GID", permissionID, BinaryOperatorType.Equal));
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityPermission), criteria);
            if (xpCollection.Count == 1)
            {
                XPSecurityPermission SecurityPermission = (XPSecurityPermission) xpCollection[0];
                return SecurityPermission;
            }
            return null;
        }


        public ISecurityPermission[] GetPermissions(Guid roleID, Guid documentID)
        {
            CriteriaOperatorCollection criteriaOperatorCollection = new CriteriaOperatorCollection();
            criteriaOperatorCollection.Add(new BinaryOperator("SecurityRoleID", roleID));
            criteriaOperatorCollection.Add(new BinaryOperator("SecuredDocumentID", documentID));

            CriteriaOperator criteriaOperator = new GroupOperator(GroupOperatorType.And, criteriaOperatorCollection);
            XPCollection<XPSecurityPermission> permissionCollection =
                new XPCollection<XPSecurityPermission>(criteriaOperator);

            ISecurityPermission[] securityPermissions = new ISecurityPermission[permissionCollection.Count];
            int index = 0;
            while (index < permissionCollection.Count)
            {
                securityPermissions[index] = permissionCollection[index];
                index++;
            }

            return securityPermissions;
        }

        //TODO: Review and see if IsGranded should be implemented
        public bool IsGranted(Guid roleID, Guid documentID, Guid actionID, Guid stateID)
        {
            throw new NotImplementedException();

            //XPCollection<XPSecurityPermission> securityPermissions = GetPermissions(roleID, documentID, actionID,stateID);

            //if(securityPermissions.Count>0)
            //{
            //    Debug.Write(securityPermissions.Count);
            //}

            //int allowed = 0;

            //foreach (XPSecurityPermission securityPermission in securityPermissions)
            //{
            //    if (securityPermission.AccessType == AccessType.Allow)
            //        allowed++;

            //    if (securityPermission.AccessType == AccessType.Deny)
            //        return false;
            //}
            //return allowed > 0;
        }

        //TODO: Review and see if IsAnyGranted should be implemented
        public bool IsAnyGranted(Guid[] roleIDs, Guid documentID, Guid actionID, Guid stateID)
        {
            throw new NotImplementedException();
        }


        public void Clear()
        {
            XPCollection<XPSecurityPermission> xpCollection = new XPCollection<XPSecurityPermission>();
            xpCollection.Session.Delete(xpCollection);
            xpCollection.Session.PurgeDeletedObjects();
        }
    }
}